home *** CD-ROM | disk | FTP | other *** search
- #define CONNECTION_C
- #include "Connection.h"
- #include "Abalone.h"
-
-
- #if defined(__MWERKS__)
- #pragma segment __%Main
- #else
- #pragma segment Main
- #endif
-
-
- static AEAddressDesc address[kPlayers+1];
-
-
- Boolean
- Connected (void)
- {
- return gSet.Connected [blak] || gSet.Connected [whit] || gSet.Connected [grin];
- }
-
-
-
- PPCFilterUPP portFilterUPP = 0;
-
-
- void
- InitConnection(void)
- {
- short p;
- Boolean netPlayerSelected = false;
-
- if (!portFilterUPP) portFilterUPP = NewPPCFilterProc (AbalonePortFilter);
-
- // In principal, we could try to restore the old connections.
- // Because I don't, the connect state must be reset.
-
- for (p = blak; p <= gSet.Players; p++)
- {
- gSet.Connected[p] = false;
- }
-
- // Check to see if we have network players at all.
- // If not, don't bother establishing any kind of connection.
-
- for (p = blak; p <= gSet.Players; p++)
- {
- if (gSet.PlayerKind[p] == networkPlayer)
- {
- netPlayerSelected = true;
- break;
- }
- }
-
- if (! netPlayerSelected)
- return;
-
- // There are net players selected.
- // Give the user a chance to determine what to do now.
-
- portFilterUPP = NewPPCFilterProc (AbalonePortFilter);
-
- CurrentCursor (arrowCursor);
- switch (Alert (rConnection, nil))
- {
- case 1: // Establish Connection
- ConnectionProtocol();
- break;
-
- case 2: // Wait for other
-
- ;
-
- break;
-
- case 3: // Cancel net play
-
- // Cancelling is done by replacing all net players by mac players.
-
- for (p = blak; p <= gSet.Players; p++)
- {
- if (gSet.PlayerKind[p] == networkPlayer)
- {
- ClearNetAddress (p);
- gSet.PlayerKind[p] = macPlayer;
- }
- }
- break;
- }
- }
-
-
-
- AEAddressDesc *
- GetNetAddress (short player)
- {
- Assert (IsConnected(player), INTERNAL_ERROR);
- return & address[player];
- }
-
-
-
- void
- SetNetAddress (AEAddressDesc *newAddress, short player)
- {
- if (IsConnected(player))
- AEDisposeDesc (& address[player]);
-
- gSet.Connected[player] = (AEDuplicateDesc (newAddress, & address[player]) == noErr);
- }
-
-
-
- void
- ClearNetAddress (short player)
- {
- if (IsConnected(player))
- AEDisposeDesc (& address[player]);
-
- gSet.Connected[player] = false;
- }
-
-
-
- Boolean
- IsConnected (short player)
- {
- return gSet.Connected[player];
- }
-
-
-
- Boolean
- ConnectState (SettingsPtr settings, short player)
- {
- return settings->Connected[player];
- }
-
-
-
- void
- BreakConnections (void)
- {
- short p, q;
- OSErr error;
-
- for (p = blak; p <= gSet.Players; p++)
- {
- if (! IsNetPlayer (& gSet, p) || ! IsConnected (p))
- continue;
-
- for (q = blak; q <= gSet.Players; q++)
- {
- if (gSet.PlayerKind[q] != networkPlayer)
- {
- error = SendAEStop (GetNetAddress(p), q);
- }
- }
- ClearNetAddress(p);
- }
- }
-
-
-
- void
- ReSyncProtocol (void)
- {
- short p;
-
- for (p = blak; p <= gSet.Players; p++)
- {
- if (! IsNetPlayer (& gSet, p) || ! IsConnected (p))
- continue;
-
- SynchronisationProtocol (p);
- }
- }
-
-
-
- void
- SynchronisationProtocol (short p)
- {
- Game serverGame;
- Board serverBoard;
-
- if (SendAEGame (& address[p], & gTheGame, CurrentBoard(), & serverGame, & serverBoard) != noErr)
- return;
-
- if (CheckSum (& serverBoard) != CheckSum (CurrentBoard()))
- {
- if (serverGame.CurrentMove <= gTheGame.CurrentMove)
- {
- Warning (OUT_OF_SYNC);
-
- gTheGame = serverGame;
- CopyBoard (& serverBoard, CurrentBoard());
- gTheGame.Board = CurrentBoard();
- InvalBoard();
- }
- // else: the other side handles this
- }
- }
-
-
-
- OSErr
- ConnectionProtocol (void)
- {
- Str255 prompt, label;
- OSErr error = noErr;
- short p, q;
- Settings wantedSet;
- Settings serverSet;
- long serverCheckSum;
- AEAddressDesc netAddress;
- Boolean protocolDone = false;
-
- for (p = blak; ! protocolDone && p <= gSet.Players; p++)
- {
- if (! IsNetPlayer (& gSet, p))
- continue;
-
- if (IsConnected (p))
- break;
-
- GetIndString (prompt, rPPCStrings, 1);
- GetIndString (label, rPPCStrings, 2);
-
- error = MakeTarget ( & netAddress,
- false,
- kAEWaitReply,
- prompt,
- label,
- portFilterUPP
- );
-
- if (error == noErr)
- {
- // We have a valid net address to establish a connection with.
- // Show the other side our current settings, and get the requested settings.
-
- wantedSet = gSet;
- error = SendAEInit (& netAddress, & wantedSet, & serverSet, & serverCheckSum);
- }
- if (error == noErr)
- {
- // We have a valid reply from the server as well.
- // We should set our settings as requested.
-
- gSet = wantedSet;
-
- // If we have a valid reply, we now have the other sides settings,
- // which means we know which address to use for all players the server handles!
-
- for (q = blak; q <= serverSet.Players; q++)
- if (! IsNetPlayer (& serverSet, q))
- SetNetAddress (& netAddress, q);
-
- // The net address has been copied by all who need it;
- // it can and should be disposed.
-
- AEDisposeDesc (& netAddress);
-
- // Handle out-of-sync problems.
- // We have a valid connection, so if we have an out-of-sync,
- // we should be able to ask for the right board.
-
-
- if ( serverCheckSum != CheckSum (CurrentBoard()))
- {
- SynchronisationProtocol (p);
- }
-
- // Request the server a broadcast of net addresses (my own, among others).
-
- error = SendAENew1 (& netAddress, & gSet);
-
- // Because we broadcast the addresses, we don't need more than 1 good connection.
-
- protocolDone = true;
- }
- else switch (error)
- {
- case missingDataErr:
- Warning (PPC);
- case noConnectionErr:
- default:
- CurrentCursor (arrowCursor);
- switch (Alert (403, nil))
- {
- case 1: // Retry connecting
- --p;
- break;
- case 2: // Wait for other
- protocolDone = true;
- break;
- case 3: // Cancel net play
- CancelNetPlay();
- protocolDone = true;
- break;
- }
- break;
- }
- }
- return error;
- }
-
-
-
- OSErr
- BroadcastMove (MovePtr move, short player, long checksum)
- {
- short p;
- OSErr error = noErr;
-
- // Send this game to all known network players
-
- for (p = blak; p <= gSet.Players; p++)
- {
- if (gSet.PlayerKind[p] != networkPlayer)
- continue;
-
- if (! IsConnected(p)) // try to restore connection
- ConnectionProtocol();
-
- if (! IsConnected(p)) // connection not restored
- continue;
-
- error = SendAEMove (GetNetAddress(p), move, player, checksum);
-
- switch (error)
- {
- case noErr:
- default:
- break;
-
- case outOfSyncErr:
- SynchronisationProtocol (p);
- break;
-
- case illegalMoveErr:
- case duplicateMoveErr:
- error = noErr;
- break;
- }
- }
- return error;
- }
-
-
-
- // Don't allow PPCBrowser to show any applications other than Abalone.
-
- pascal Boolean AbalonePortFilter (LocationNamePtr locationName, PortInfoPtr thePortInfo)
- {
- #if ! defined(__MWERKS__) && ! defined (__SC__)
- #pragma unused(locationName)
- #endif
-
- long type;
-
- if (thePortInfo->name.portKindSelector == ppcByString)
- {
- BlockMove (thePortInfo->name.u.portTypeStr + 1, (Ptr)&type, 4);
- if (type == 'A•1e')
- return true;
- }
- return false;
- }
-
-
-
-
-
- #ifdef NETDEBUG
- void
- DoNetTestMenu (short menuItem)
- {
- static AEAddressDesc gOpponent;
- OSErr error;
-
- switch (menuItem)
- {
- case NETTEST_CONNECT:
- gSet.Connected[0] = gSet.Connected[1] = gSet.Connected[2] = gSet.Connected[3] = false;
- error = ConnectionProtocol();
- break;
- case NETTEST_MOVE:
- // The last move made is stored in a global gLastMove.
- // This can be sent to a different Abalone process.
- BroadcastMove (gLastMove, PriorPlayer (CurrentPlayer()), CheckSum (RecentBoard()));
- break;
- case NETTEST_GAME:
- // For testing, the current game is sent to the other side.
-
- SendAEGame (GetNetAddress(NextPlayer(gTheGame.CurrentPlayer)), & gTheGame);
-
- break;
- case NETTEST_UNDO:
- break;
- default:
- Assert (false, DEFAULT_IN_CASE);
- }
- }
- #endif
-
-
-
- void
- MatchSettings (SettingsPtr smpl, SettingsPtr sets)
- {
- short p;
-
- Assert (sets->Version == smpl->Version, DIFFERENT_VERSION_ERROR);
-
- // Match the number of players
- sets->Players = smpl->Players;
-
- // Don't care about personal preferences over there:
- // Leave stuff like FieldWidth and SounOn alone.
-
- // Match the player types.
- // This is the hard part, when we assume the settings need not be complementary.
-
- for (p = 1; p <= smpl->Players; p++)
- {
- if (IsMacPlayer (smpl, p))
- {
- if (IsMacPlayer (sets, p))
- {
- SetPlayerKind (sets, p, networkPlayer);
- }
- else if (IsHumanPlayer (sets, p))
- {
- SetPlayerKind (smpl, p, networkPlayer);
- }
- else // IsNetPlayer (sets, p)
- {
- Boolean forceHuman = ! ConnectState (sets, p)
- && (CountHumanPlayers (sets) == 0);
-
- if (forceHuman)
- {
- SetPlayerKind (sets, p, humanPlayer);
- SetPlayerKind (smpl, p, networkPlayer);
- }
- }
- }
- else if (IsHumanPlayer (smpl, p))
- {
- if (IsMacPlayer (sets, p))
- {
- SetPlayerKind (sets, p, networkPlayer);
- }
- else if (IsHumanPlayer (sets, p))
- {
- SetPlayerKind (sets, p, networkPlayer);
- }
- else // IsNetPlayer (sets, p)
- {
- ;
- }
- }
- else // IsNetPlayer (smpl, p)
- {
- if (IsMacPlayer (sets, p))
- {
- ;
- }
- else if (IsHumanPlayer (sets, p))
- {
- ;
- }
- else // IsNetPlayer (sets, p)
- {
- Boolean forceHuman = smpl->Players == 2
- || (! ConnectState (smpl, p) && ! ConnectState (sets, p));
- if (forceHuman)
- SetPlayerKind (sets, p, humanPlayer);
-
- }
- }
- }
-
- if (CountHumanPlayers (sets) == 0)
- {
- // After making the changes above, the other side doesnt' have a human player left,
- // we can see if we have a slot left we can assign to him.
-
- for (p = 1; p <= smpl->Players; p++)
- {
- if (IsMacPlayer (smpl, p))
- {
- // So we do. Assign it to him.
-
- SetPlayerKind (sets, p, humanPlayer);
- break; // one will do; others should have a chance as well.
- }
- }
- }
-
- // Over here, the settings are as good as they will be, so assume them OK.
-
- // Match the names
-
- for (p = 1; p <= smpl->Players; p++)
- {
- if (smpl->PlayerKind[p] == humanPlayer)
- {
- // Tell the other side our name
-
- strcpy (sets->PlayerName[p], smpl->PlayerName[p]);
- }
- if (sets->PlayerKind[p] == humanPlayer)
- {
- // Be so polite as to use his own name
-
- strcpy (smpl->PlayerName[p], sets->PlayerName[p]);
- }
- }
- }
-
-
-
- void
- CancelNetPlay (void)
- {
- short p;
-
- BreakConnections(); // just to be sure
-
- // Cancelling is done by replacing all net players by mac players.
-
- for (p = blak; p <= gSet.Players; p++)
- {
- if (IsNetPlayer (& gSet, p))
- {
- ClearNetAddress (p);
- SetPlayerKind (& gSet, p, macPlayer);
- }
- }
- }
-